//
//  Codable+Extension.swift
//  SwiftCode
//
//  Created by yuhus on 2024/1/25.
//

import Foundation

/// 所有Domain层Entity实现这个协议
public protocol SinkEntity: Codable, Equatable { }
/// 所有Data层DTO实现这个协议
public protocol DTOType: Codable { }

public protocol SinkEntityConvertibleDTOType: DTOType {
  associatedtype DomainType: SinkEntity
  /// 把DTO类型转换成Entity类型，实现Data层和Domain层的数据解耦
  /// 如果无法自动类型推断，需要在参数里面传入类型协助进行类型推断。
  /// 注意依赖关系，Data层单向依赖Domain层的SinkEntityConvertibleDTOType协议，Domain层不依赖Data层
  /// - Returns: Entity类型
  func asDomainType() -> DomainType?
  
  func asDomainType<A>(_ additions: A) -> DomainType?
}

public extension SinkEntityConvertibleDTOType {
  func asDomainType<A>(_ additions: A) -> DomainType? {
    asDomainType()
  }
}

public protocol ResponseType: Codable {
  associatedtype C: Codable
  
  var data: C { get }
}

public struct ResponseDTO<C: Codable>: ResponseType {
  public let code: Int
  public let message: String
  public let data: C?
}

public protocol DefaultValueProviding {
  static var defaultValue: Self { get }
}

public protocol IcarusCodable: Codable, DefaultValueProviding { }

extension Int: IcarusCodable {
  public static var defaultValue: Int { 0 }
}

extension String: IcarusCodable {
  public static var defaultValue: String { "" }
}

extension Double: IcarusCodable {
  public static var defaultValue: Double { 0.0 }
}

extension Bool: IcarusCodable {
  public static var defaultValue: Bool { false }
}

extension Optional: DefaultValueProviding {
  public static var defaultValue: Self { .none }
}

extension Optional: IcarusCodable where Wrapped: IcarusCodable {
  public static var defaultValue: Optional<Wrapped> { .none }
}

extension Dictionary: DefaultValueProviding {
  public static var defaultValue: Self { [:] }
}

extension Dictionary: IcarusCodable where Value: IcarusCodable, Key: IcarusCodable {
  public static var defaultValue: Dictionary<Key, Value> { [:] }
}

extension Array: DefaultValueProviding {
  public static var defaultValue: Self { [] }
}

extension Array: IcarusCodable where Element: IcarusCodable {
  public static var defaultValue: Array<Element> { [] }
}
